#include <unistd.h>

#include <cmath>
#include <functional>
#include <future>
#include <iostream>
#include <thread>

// 1.future
// int async_test() {
//     sleep(5);
//     return 42;
// }
// void ready_task() {
//     for (int i = 0; i < 10; i++) {
//         std::cout << i << std::endl;
//     }
// }
// // async - std::launch::deferred | std::launch::async
// // std::future::get()用于获取并返回任务的结果
// // std::future::wait()只是等待任务完成
// void future_test() {
//     std::future<int> fut = std::async(async_test);
//     ready_task();
//     std::cout << fut.get() << std::endl;
// }

// 2.packaged_task()代码演示
// std::string wait_task() {
//     sleep(2);
//     return "man!what can I say,manba out";
// }

// void package_task_test() {
//     std::packaged_task<std::string()> task(wait_task);
//     std::future fut = task.get_future();

//     std::thread t(std::move(task));
//     t.detach();

//     std::string value = fut.get();
//     std::cout << value << std::endl;
// }

// 3.promise的简单使用
// void getpromise(std::promise<int> prom) {
//     // 设置promise的value
//     sleep(2);
//     prom.set_value(10);
//     sleep(5);
// }

// void getvalue() {
//     std::promise<int> prom;
//     std::future<int> fut = prom.get_future();
//     std::thread t(getpromise, std::move(prom));
//     std::cout << fut.get() << std::endl;
//     t.join();
// }

// 4.promise的set_exception()方法
// future抛出异常
// double square_root(double x) {
//     if (x < 0) {
//         throw std::out_of_range("x < 0");
//     }
//     return std::sqrt(x);
// }
// void exception_test() {
//     // square_root(-1);
//     std::future<double> f = std::async(square_root, -1);
//     try {
//         std::cout << "Waiting for the thread to set the exception...\n";
//         double y = f.get();
//     } catch (const std::exception& e) {
//         std::cout << "Exception set by the thread: " << e.what() << '\n';
//     }
// }
// promise接收的
// void set_exception(std::promise<void> prom) {
//     try {
//         // 抛出一个异常
//         throw std::runtime_error("An error occurred!");
//     } catch (...) {
//         // 设置 promise 的异常
//         prom.set_exception(std::current_exception());
//     }
// }
// void set_exception_test() {
//     std::promise<void> prom;
//     std::future fut = prom.get_future();
//     std::thread t(set_exception, std::move(prom));
//     try {
//         std::cout << "Waiting for the thread to set the exception...\n";
//         fut.get();
//     } catch (const std::exception& e) {
//         std::cout << "Exception set by the thread: " << e.what() << '\n';
//     }
//     // t.join();
// }

// 5.future权利转移与shared_future
// void promiseFunc(std::promise<int>&& prom) {
//     sleep(2);
//     prom.set_value(42);
// }

// void thread_future(std::future<int> fut) {
//     try {
//         int result = fut.get();
//         std::cout << "Result: " << result << std::endl;
//     } catch (const std::future_error& e) {
//         std::cout << "Future error: " << e.what() << std::endl;
//     }
// }

// void thread_shared_fut(std::shared_future<int>& fut) {
//     try {
//         int result = fut.get();
//         std::cout << "Result: " << result << std::endl;
//     } catch (const std::future_error& e) {
//         std::cout << "Future error: " << e.what() << std::endl;
//     }
// }

// void Pow_move() {
//     std::promise<int> promise;
//     // std::future<int> future = promise.get_future();
//     std::shared_future<int> future = promise.get_future();
//     std::thread PromThread(promiseFunc, std::move(promise));
//     // std::thread FutThread(thread_future, std::move(future));

//     // void thread_shared_fut(std::shared_future<int> fut)
//     // std::thread FutThread1(thread_shared_fut, future);

//     std::thread FutThread1(thread_shared_fut, std::ref(future));
//     std::thread FutThread2(thread_shared_fut, std::ref(future));
//     std::thread FutThread3(thread_shared_fut, std::ref(future));

//     PromThread.join();
//     // FutThread.join();

//     FutThread1.join();
//     FutThread2.join();
//     FutThread3.join();
// }

// // funture->shared_future
// void tranPow() {
//     std::promise<int> p;
//     std::future<int> f(p.get_future());
//     assert(f.valid());  // 1 "期望" f 是合法的
//     std::shared_future<int> sf(std::move(f));
//     assert(!f.valid());  // 2 "期望" f 现在是不合法的
//     assert(sf.valid());  // 3 sf 现在是合法的
// }

// 6.线程池 future版本
#include <atomic>
#include <condition_variable>
#include <future>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

#ifndef __THREAD_POOL_H__
#define __THREAD_POOL_H__

class ThreadPool {
   public:
    using Task = std::packaged_task<void()>;  // 任务打包
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;

    static ThreadPool* GetInit() {
        if (_pointer != nullptr) return _pointer;

        _pmtx.lock();
        if (_pointer == nullptr) {
            _pointer = new ThreadPool();
        }
        _pmtx.unlock();
        return _pointer;
    }

    ~ThreadPool() { stop(); }

    int Suspend_num() { return _num_thread; }

    // 想传入的是应该函数 - int Func(int,std::string)
    template <class F, class... Args>
    auto Commit(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
        using RetType = decltype(f(args...));
        if (_stop.load()) {  // 停止时无法获取值,外面future.get()记得try-catch
            return std::future<RetType>{};
        }

        // 把带参数的函数绑定成不带参数的函数
        auto task = std::make_shared<std::packaged_task<RetType()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...));

        std::future<RetType> ret = task->get_future();
        {
            std::lock_guard<std::mutex> lock(_mtx);
            _task.emplace([task] { (*task)(); });
        }
        _cond.notify_one();
        return ret;
    }

   private:
    ThreadPool(u_int num = std::thread::hardware_concurrency())
        : _stop(false), _num_thread(num <= 1 ? 2 : num) {
        start();
    }

    void start() {
        for (int i = 0; i < _num_thread; i++) {
            _pool.emplace_back([this]() {
                while (!this->_stop.load()) {
                    Task task;
                    {
                        std::unique_lock<std::mutex> lock(this->_mtx);
                        this->_cond.wait(lock, [this] {
                            return this->_stop.load() || !this->_task.empty();
                        });
                        if (this->_task.empty()) return;

                        task = std::move(this->_task.front());
                        this->_task.pop();
                    }
                    --_num_thread;
                    task();
                    ++_num_thread;
                }
            });
        }
    }

    void stop() {
        _stop.store(true);
        _cond.notify_all();
        for (auto& td : _pool) {
            if (td.joinable()) {
                std::cout << "join thread " << td.get_id() << std::endl;
                td.join();
            }
        }
    }

   private:
    std::mutex _mtx;
    std::condition_variable _cond;
    std::atomic_bool _stop;
    std::atomic_int _num_thread;
    std::vector<std::thread> _pool;
    std::queue<Task> _task;
    static ThreadPool* _pointer;
    static std::mutex _pmtx;
};

ThreadPool* ThreadPool::_pointer = nullptr;
std::mutex ThreadPool::_pmtx;

#endif  // !__THREAD_POOL_H__

std::string poolfunc(int a, int b, std::string str) {
    std::cout << a << " " << b << std::endl;
    std::string ret = "I say: " + str;
    return ret;
}

int main() {
    // future_test();
    // package_task_test();
    // getvalue();
    // exception_test();
    // set_exception_test();
    // Pow_move();
    ThreadPool* pool = ThreadPool::GetInit();
    try {
        std::future fut = pool->Commit(poolfunc, 1, 2, "hello world");
        // delete pool;
        auto result = fut.get();
        std::cout << result << std::endl;
    } catch (const std::exception& e) {
        printf("No thread_pool deal with task\n");
        std::cerr << e.what() << '\n';
    }

    return 0;
}